/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import { HvigorCoreNode, Module, Project } from '../../external/core/hvigor-core-node.js';
import { HvigorLogger } from '../../log/hvigor-log.js';
import { projectTaskDag, TaskDirectedAcyclicGraph } from '../task/core/task-directed-acyclic-graph.js';
import { parseTaskPath } from '../task/util/task-path-util.js';

const _log = HvigorLogger.getLogger('hvigor-build-task-graph');
const taskPathCache: Map<string, { moduleName: string; taskName: string }> = new Map();

/**
 * 构建每个hvigor module的Task DAG图
 *
 * @param {Project} project
 */
export function buildTaskGraph(project: Project): void {
  project.getSubModules().forEach((module: HvigorCoreNode) => buildGraph(module, module.getTaskPaths(), module.getTaskGraph()));

  buildGraph(project, project.getTaskPaths(), project.getTaskGraph());

  /**
   * 只需检查整个工程的DAG图
   */
  const { hasCircle, circlePath } = projectTaskDag.checkCircle();
  if (hasCircle) {
    const errMsg = `Circular dependency between the following tasks: ${circlePath.join(' -> ')}`;
    _log.errorMessageExit(errMsg);
  }
}

function buildGraph(node: HvigorCoreNode, tasks: string[], taskGraph: TaskDirectedAcyclicGraph): void {
  const modules: Map<string, Module> = node.getProject().getSubModules();
  tasks.forEach((task: string) => {
    const { moduleName, taskName } = parseTaskPathWithCache(task);
    const taskNode: Module | undefined = moduleName === '' ? node.getProject() : modules.get(moduleName);
    if (taskNode === undefined) {
      _log.printErrorExit('CANNOT_FIND_HVIGOR_NODE',[moduleName, task]);
      return;
    }
    for (const dependsOnTaskPath of node.getTaskDepends(taskName)) {
      const { moduleName: dependNode, taskName: dependTask } = parseTaskPathWithCache(dependsOnTaskPath);
      const dependentNode = dependNode === '' ? node.getProject() : modules.get(dependNode);
      if (dependentNode === undefined) {
        _log.printErrorExit('CANNOT_FIND_HVIGOR_DEPEND_NODE',[dependNode, dependTask]);
        return;
      }
      if (!dependentNode.hasTask(dependTask)) {
        _log.printErrorExit('CANNOT_FIND_HVIGOR_TASK', [dependTask, dependNode, task]);
      }
      taskGraph.addEdge(task, dependsOnTaskPath);
      projectTaskDag.addEdge(task, dependsOnTaskPath);
    }
  });
}

const parseTaskPathWithCache = (taskPath: string) => {
  let parsedPath: { moduleName: string; taskName: string } | undefined = taskPathCache.get(taskPath);
  if (parsedPath !== undefined) {
    return parsedPath;
  }
  parsedPath = parseTaskPath(taskPath);
  taskPathCache.set(taskPath, parsedPath);
  return parsedPath;
};
